package com.tek271.funj;
import com.google.common.base.Joiner;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.mvel2.MVEL;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
public class ReflectionTools {
/**
* get the value of a property
* @param obj container object
* @param propertyName name of property
* @param <OBJ> generic type of container object
* @param <PROP> generic type of property
* @return the value of the property
* @throws IllegalArgumentException if obj is null, or if propertyName is null,
* empty, blank, or does not exist.
*/
@SuppressWarnings("unchecked")
public static <OBJ, PROP> PROP getPropertyValue(OBJ obj, String propertyName) {
if (obj==null) {
throw new IllegalArgumentException("The container object cannot be null");
}
if (StringUtils.isBlank(propertyName)) {
throw new IllegalArgumentException("propertyName is required");
}
try {
return (PROP) MVEL.eval(propertyName, obj);
} catch(Exception e) {
throw new IllegalArgumentException(e);
}
}
/**
* Check if the property exists on the given object
* @param obj container object
* @param propertyName name of property
* @param <OBJ> generic type of container object
* @throws IllegalArgumentException if propertyName does not exist
*/
public static <OBJ> void checkPropertyExists(OBJ obj, String propertyName) {
getPropertyValue(obj, propertyName);
}
public static <OBJ> void checkPropertiesExist(OBJ obj, String... propertyNames) {
for (String propertyName: propertyNames) {
getPropertyValue(obj, propertyName);
}
}
/**
* Check if the 1st item in the iterable has the given propertyName
* @param iterable some objects
* @param propertyName name of property
* @param <OBJ> generic type of the iterable element
* @throws IllegalArgumentException if propertyName does not exist
*/
public static <OBJ> void checkPropertyExists(Iterable<OBJ> iterable, String propertyName) {
getPropertyValue(iterable.iterator().next(), propertyName);
}
public static <OBJ> void checkPropertiesExist(Iterable<OBJ> iterable, String... propertyNames) {
checkPropertiesExist(iterable.iterator().next(), propertyNames);
}
@SuppressWarnings("unchecked")
public static <OUT> OUT callStatic(String fullFunctionName, Object... args) {
Pair<String, Map<String, Object>> pair = buildArgs(args);
String func = createFunctionCall(fullFunctionName, pair.getLeft());
return (OUT) MVEL.eval(func, pair.getRight());
}
public static <OUT> OUT callStatic(Class cls, String functionName, Object... args) {
String fullFunctionName = cls.getName() + "." + functionName;
return callStatic(fullFunctionName, args);
}
@SuppressWarnings("unchecked")
public static <OUT> OUT callMethod(Object context, String functionName, Object... args) {
Pair<String, Map<String, Object>> pair = buildArgs(args);
String func = createFunctionCall(functionName, pair.getLeft());
return (OUT) MVEL.eval(func, context, pair.getRight());
}
private static String createFunctionCall(String functionName, String args) {
functionName = removeEndParens(functionName);
return functionName + "(" + args + ")";
}
private static String removeEndParens(String funcName) {
if (StringUtils.endsWith(funcName, "()")) {
return StringUtils.left(funcName, funcName.length()-2);
}
return funcName;
}
private static Pair<String, Map<String, Object>> buildArgs(Object... args) {
Map<String, Object> map = newHashMap();
List<String> varNames = newArrayList();
int i=0;
for (Object arg: args) {
String varName = "arg" + i;
varNames.add(varName);
map.put(varName, arg);
i++;
}
return Pair.of(Joiner.on(',').join(varNames), map);
}
}